package org.nimi317.web_gis.task;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.nimi317.web_gis.Enum.JobEnum;
import org.nimi317.web_gis.annotation.JobClass;
import org.nimi317.web_gis.annotation.JobMethod;
import org.nimi317.web_gis.context.SecurityContextHolder;
import org.nimi317.web_gis.data.AreaCodeList;
import org.nimi317.web_gis.entity.Area;
import org.nimi317.web_gis.entity.StationQuality;
import org.nimi317.web_gis.exception.RException;
import org.nimi317.web_gis.service.*;
import org.nimi317.web_gis.service.impl.AreaCodeException;
import org.nimi317.web_gis.utils.TimeUtils;
import org.springframework.context.annotation.Lazy;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 定时任务
 *
 * @author thunderobot
 */
@Slf4j
@JobClass
public class AirQualityRealTask {

    private final IStationQualityService qualityService;

    private final IStationService stationService;

    private final IAreaQualityService areaQualityService;

    private final AreaCodeList areaCodeList;

    private final IAreaWeatherService areaWeatherService;

    private final ITableRangeService tableRangeService;

    private final IUpdateService service;

    private final ScheduledTask scheduledTask;

    private boolean update;

    private final IStationQualityService stationQualityService;

    private final IJobService jobService;

    private final ProvinceQualityService provinceQualityService;

    public AirQualityRealTask(IStationQualityService qualityService, IStationService stationService, IAreaQualityService areaQualityService, AreaCodeList areaCodeList, IAreaWeatherService areaWeatherService, ITableRangeService tableRangeService, IUpdateService service, @Lazy ScheduledTask scheduledTask, IStationQualityService stationQualityService, @Lazy IJobService jobService, ProvinceQualityService provinceQualityService) {
        this.qualityService = qualityService;
        this.stationService = stationService;
        this.areaQualityService = areaQualityService;
        this.areaCodeList = areaCodeList;
        this.areaWeatherService = areaWeatherService;
        this.tableRangeService = tableRangeService;
        this.service = service;
        this.scheduledTask = scheduledTask;
        this.stationQualityService = stationQualityService;
        this.jobService = jobService;
        this.provinceQualityService = provinceQualityService;
    }

    // 每小时20点执行
    @JobMethod
    public void task() {
        synchronized (AirQualityRealTask.class) {
            updateAirQualityData();
        }
    }

    public void updateAirQualityData() {
        if (update) {
            remedyEnd();
            return;
        }
        try {
            log.info("开始更新监测点数据");
            boolean b = qualityService.updateQualityData();
            if (!b) {
                // 更新失败进行增加定时任务 时长是每五分钟一次
                remedy();
                return;
            }
        } catch (AreaCodeException e) {
            log.info("编码获取错误", e);
            return;
        }
        //更新成功
        remedyEnd();
        LocalDateTime lastUpdateTime = stationQualityService.getLastUpdateTime();
        SecurityContextHolder.setLastTime(lastUpdateTime);
        log.info("开始输出市区质量数据");
        try {
            areaQualityService.updateAreaQualityData();
            provinceQualityService.updateProvinceQualityData();
            tableRangeService.updateCurrentRange(areaCodeList.getTableName());
            service.updateTime();
            this.update = TimeUtils.getCurrentUsefulDateTime().equals(lastUpdateTime);
        } catch (Exception e) {
            this.update = false;
        }
        SecurityContextHolder.remove();
    }

    @JobMethod
    public void stationTask() {
        log.info("开始更新站点");
        stationService.updateStationData();
    }

    //每个小时5分钟执行
    @JobMethod
    public void weatherTask() {
        log.info("开始更新天气数据");
        List<Area> list = areaCodeList.getAreaCodes().stream().filter(s -> s.getCode() != null).toList();
        for (Area s : list) {
            areaWeatherService.refreshWeather(s);
        }
    }

    public boolean getUpdate() {
        return update;
    }

    public void setUpdate(boolean update) {
        this.update = update;
    }

    private void remedy() {
        LocalDateTime lastUpdateTime = stationQualityService.getLastUpdateTime();
        LambdaQueryWrapper<StationQuality> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StationQuality::getTimestamp, lastUpdateTime);
        stationQualityService.remove(wrapper);
        if (!jobService.getJobById(JobStrategy.Recycle).getStatus().equals(JobEnum.Running)) {
            scheduledTask.start(JobStrategy.Recycle);
            jobService.start(JobStrategy.Recycle);
        }
    }

    private void remedyEnd() {
        scheduledTask.stop(JobStrategy.Recycle);
        try {
            jobService.stop(JobStrategy.Recycle);
        } catch (RException e) {
            log.info("停止任务失败");
        }
    }

    @JobMethod
    public void updateTask() {
        this.update = false;
    }

    private static class JobStrategy {
        private static final int Recycle = 9;
    }
}
